flutter网络请求dio的get、post、上传文件、下载文件总结

您所在的位置:网站首页 flutter 上传文件 flutter网络请求dio的get、post、上传文件、下载文件总结

flutter网络请求dio的get、post、上传文件、下载文件总结

2024-06-20 00:26| 来源: 网络整理| 查看: 265

题记 —— 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天。

重要消息

flutter中网络请求dio使用分析 视频教程在这里Flutter 从入门实践到开发一个APP之UI基础篇 视频Flutter 从入门实践到开发一个APP之开发实战基础篇flutter跨平台开发一点一滴分析系列文章系列文章 在这里了

本文章将讲述 1.使用dio发送基本的get请求 2.使用dio发送get请求的传参方式 3.解析响应json数据 4.使用dio发送post请求并提交FormData参数 5.使用dio发送post请求并提交json参数 6.使用dio上传文件并实现进度监听 7.使用dio下载文件并实现进度监听 8.配制dio的拦截器 9.配制dio网络代理抓包 10.配制dio请求header以及公共请求参数 11.dio 取消网络请求

1 引言

dio用来在flutter跨平台开发中访问网络的框架,在使用的时候,我们首先是引入依赖

dependencies: dio: 3.0.9

也可以访问国内pub仓库来查看 dio的最新版本。

一般添加依赖如下所示

dependencies: dio: ^3.0.9

两种写法的差别是 ^在每次 flutter pub get 是会有小版本的自动升级,不添加这个符号就不会有自动小升级

2 Dio get请求 2.1 Dio get 请求无参数 //get请求无参数 void getRequestFunction1() async { ///创建Dio对象 Dio dio = new Dio(); ///请求地址 获取用户列表 String url = "http://192.168.0.102:8080/getUserList"; ///发起get请求 Response response = await dio.get(url); ///响应数据 var data = response.data; setState(() { result = data.toString(); }); }

数据响应结果

{ "code": 200, "data": [ { "id": 3, "userName": "测试人员", "realName": "张三", "age": 22 } ], "message": "请求成功" }

断点调试如下 在这里插入图片描述

2.2 Dio get 请求有参数 ///get请求有参数 ///根据用户ID来获取用户信息 void getRequestFunction2() async { ///用户id int userId =3; ///创建 dio Dio dio = new Dio(); ///请求地址 ///传参方式1 String url = "http://192.168.0.102:8080/getUser/$userId"; ///传参方式2 String url2 = "http://192.168.0.102:8080/getUser?userId=$userId"; ///传参方式 3 String url3 = "http://192.168.0.102:8080/getUser"; Map map = Map(); map["userId"]= userId; ///发起get请求 Response response = await dio.get(url3,queryParameters: map); ///响应数据 Map data = response.data; /// 将响应数据解析为 UserBean UserBean userBean = UserBean.fromJson(data); } }

在上述代码中,传参方式1与传参方式2是在请求链接中拼接参数,请求方式3是将参数放在一个 map 中,然后通过 Dio 的queryParameters 来配制参数,上述返回的数据结构为

{ "code": 200, "data": { "id": 3, "userName": "测试人员", "realName": "张三", "age": 22 }, "message": "请求成功" }

断点调试 在这里插入图片描述 对于这里使用到的数据模型 UserBean 对象来说

class UserBean{ String userName; String realName; int age; int id; static UserBean fromJson(Map rootData){ ///解析第一层 Map data = rootData["data"]; ///解析第二层 UserBean userBean = new UserBean(); userBean.id = data["id"]; userBean.age = data["age"]; userBean.userName= data["userName"]; userBean.realName = data["realName"]; return userBean; } }

对于 UserBean 中的数据解析如下图所示

在这里插入图片描述 在这里插入图片描述

3 Dio post请求 2.1 Dio post 请求提交 FormData 表单数据

FormData 将提交的参数 name与value进行组合,实现表单数据的序列化,从而减少表单元素的拼接 也可以这样来描述:FormData 接口提供了一种表示表单数据的键值对的构造方式,通过FormData发出的请求编码类型被设为 “multipart/form-data”,而在网络请求访问中,通过 Content-Type 来记录这个值,可以理解为Content-Type 表示具体请求中的媒体类型信息。

而我们在实际开发中常用的 Content-Type如下

multipart/form-data application/json JSON数据格式 application/x-www-form-urlencoded 表单数据格式

下面我们将使用 dio 来发起一个post请求,提交参数的格式为 FromData

void postRequestFunction() async { ///创建Dio Dio dio = new Dio(); ///发送 FormData: FormData formData = FormData.fromMap({"name": "张三", "age": 22}); String url ="http://192.168.200.68:8080/registerUser"; ///发起 post 请求 如这里的注册用户信息 Response response = await dio .post(url, data: formData); result = response.data.toString(); setState(() {}); }

抓包所得如下 在这里插入图片描述 我们也可以看到参数的格式 在这里插入图片描述 在这里我们可以看到 Content-type 是 text/plain 而并不是我们上面所说的 multipart/form-data ,这是因为在通过Dio 的 FormData 封装参数时,会进行一步默认的设置如下图所示

在这里插入图片描述

2.2 Dio post 请求提交 json 数据

下面我们使用 dio 发起一个post请求,提交json格式的参数

///post请求发送json void postRequestFunction2() async{ String url = "http://192.168.0.102:8080/registerUser2"; ///创建Dio Dio dio = new Dio(); ///创建Map 封装参数 Map map = Map(); map['userName']="小明"; map['userAge']=44; ///发起post请求 Response response = await dio.post(url,data: map); var data = response.data; }

抓包所得如下 在这里插入图片描述 从上图中,我们可以看到 Content-Type 标识了传参方式是以 json 格式来发送的,下图中我们可以看到具体的参数 在这里插入图片描述

4 Dio 文件上传并实现进度监听 ///手机中的图片 String localImagePath ="/storage/emulated/0/Download/17306285.jpg"; ///上传的服务器地址 String netUploadUrl = "http://192.168.0.102:8080/fileupload"; ///dio 实现文件上传 void fileUplod() async{ ///创建Dio Dio dio = new Dio(); Map map = Map(); map["auth"]="12345"; map["file"] = await MultipartFile.fromFile(localImagePath,filename: "xxx23.png"); ///通过FormData FormData formData = FormData.fromMap(map); ///发送post Response response = await dio.post(netUploadUrl, data: formData, ///这里是发送请求回调函数 ///[progress] 当前的进度 ///[total] 总进度 onSendProgress: (int progress, int total) { print("当前进度是 $progress 总进度是 $total"); },); ///服务器响应结果 var data = response.data; }

通过断点调试 在这里插入图片描述 这里的上传图片请求接口返回了图片的保存路径,我们打开本地服务器的目录 在这里插入图片描述

5 Dio 文件下载并实现进度监听 ///当前进度进度百分比 当前进度/总进度 从0-1 double currentProgress =0.0; ///下载文件的网络路径 String apkUrl =""; ///使用dio 下载文件 void downApkFunction() async{ /// 申请写文件权限 bool isPermiss = await checkPermissFunction(); if(isPermiss) { ///手机储存目录 String savePath = await getPhoneLocalPath(); String appName = "rk.apk"; ///创建DIO Dio dio = new Dio(); ///参数一 文件的网络储存URL ///参数二 下载的本地目录文件 ///参数三 下载监听 Response response = await dio.download( apkUrl, "$savePath$appName", onReceiveProgress: (received, total) { if (total != -1) { ///当前下载的百分比例 print((received / total * 100).toStringAsFixed(0) + "%"); // CircularProgressIndicator(value: currentProgress,) 进度 0-1 currentProgress = received / total; setState(() { }); } }); }else{ ///提示用户请同意权限申请 } }

Android权限目前分为三种:正常权限、危险权限、特殊权限

正常权限 直接在AndroidManifest中配置即可获得的权限。大部分权限都归于此。 危险权限,Android 6.0之后将部分权限定义于此。 危险权限不仅需要需要在AndroidManifest中配置,还需要在使用前check是否真正拥有权限,以动态申请。

在ios中,使用xcode打开本目录

选中Xcode 工程中的 info.plist文件,右键选择Open As - Source Code,将权限配置的代码copy到里面即可,键值对中的内容可按项目需求相应修改。

NSPhotoLibraryUsageDescription 需要您的同意,APP才能访问相册 NSCameraUsageDescription 需要您的同意,APP才能访问相机 NSMicrophoneUsageDescription 需要您的同意,APP才能访问麦克风 NSLocationUsageDescription 需要您的同意, APP才能访问位置 NSLocationWhenInUseUsageDescription App需要您的同意, APP才能在使用期间访问位置 NSLocationAlwaysUsageDescription App需要您的同意, APP才能始终访问位置 NSCalendarsUsageDescription App需要您的同意, APP才能访问日历 NSRemindersUsageDescription 需要您的同意, APP才能访问提醒事项 NSMotionUsageDescription 需要您的同意, APP才能访问运动与健身 NSHealthUpdateUsageDescription 需要您的同意, APP才能访问健康更新 NSHealthShareUsageDescription 需要您的同意, APP才能访问健康分享 NSBluetoothPeripheralUsageDescription 需要您的同意, APP才能访问蓝牙 NSAppleMusicUsageDescription 需要您的同意, APP才能访问媒体资料库

在 flutter 项目目录中,我们也可以打开 info.plist 文件配置,如下图所示 在这里插入图片描述 在这里使用的是 permission_handler 插件来申请权限的

permission_handler: ^4.3.0

申请权限代码如下

///PermissionGroup.storage 对应的是 ///android 的外部存储 (External Storage) ///ios 的Documents` or `Downloads` checkPermissFunction() async { if (Theme.of(context).platform == TargetPlatform.android) { ///安卓平台中 checkPermissionStatus方法校验是否有储存卡的读写权限 PermissionStatus permission = await PermissionHandler() .checkPermissionStatus(PermissionGroup.storage); if (permission != PermissionStatus.granted) { ///无权限那么 调用方法 requestPermissions 申请权限 Map permissions = await PermissionHandler() .requestPermissions([PermissionGroup.storage]); ///校验用户对权限申请的处理 if (permissions[PermissionGroup.storage] == PermissionStatus.granted) { return true; } } else { return true; } } else { return true; } return false; }

申请好权限后,我们需要确定下来储存卡的路径,在这里使用的是 path_provider 插件

path_provider: 1.6.0 ///获取手机的存储目录路径 ///getExternalStorageDirectory() 获取的是 android 的外部存储 (External Storage) /// getApplicationDocumentsDirectory 获取的是 ios 的Documents` or `Downloads` 目录 Future getPhoneLocalPath() async { final directory = Theme.of(context).platform == TargetPlatform.android ? await getExternalStorageDirectory() : await getApplicationDocumentsDirectory(); return directory.path; } 6 dio 配制网络代理抓包 _setupPROXY(Dio dio) { (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (HttpClient client) { client.findProxy = (uri) { ///这里的 192.168.0.102:8888就是我们的代理服务地址 return "PROXY 192.168.0.102:8888"; }; client.badCertificateCallback = (X509Certificate cert, String host, int port) { return true; }; }; } 7 dio 配制公共请求参数

在实际应用开发中,我们会有像 token、appVersionCode 等等这些每个接口请求都需要传的参数 ,称之为公共请求参数,那么在这里 dio 的请求中我们可以考虑这样来配制

String application = "V 1.2.2"; int appVersionCode = 122; ///[url]网络请求链接 ///[data] post 请求时传的json数据 ///[queryParameters] get请求时传的参数 void configCommonPar(url,data,Map queryParameters){ ///配制统一参数 if (data != null) { data['application'] = application; data['appVersionCode'] = appVersionCode.toString(); } else if (queryParameters != null) { queryParameters['application'] = application; queryParameters['appVersionCode'] = appVersionCode.toString(); } else { ///url中有可能拼接着其他参数 if (url.contains("?")) { url += "&application=$application&appVersionCode=$appVersionCode"; } else { url += "?application=$application&appVersionCode=$appVersionCode"; } } } } 8 dio 配制Content-Type 与请求 header

我们在创建 Dio对象时,会初始化一个 BaseOptions 来创建 Dio

BaseOptions options = BaseOptions(); ///请求header的配置 options.headers["appVersionCode"]=406; options.headers["appVersionName"]="V 4.0.6"; options.contentType="application/json"; options.method="GET"; options.connectTimeout=30000; ///创建 dio Dio dio = new Dio(options);

我们也可以在每次发送 get 、post 等不同的请求时,通过 dio 获取到 默认的 options 然后修改一下

void getRequestFunction2() async { ///用户id int userId = 3; ///创建 dio Dio dio = new Dio(); ///请求地址 ///传参方式1 String url = "http://192.168.0.102:8080/getUser/$userId"; ///在这里修改 contentType dio.options.contentType="application/json"; ///请求header的配置 dio.options.headers["appVersionCode"]=406; dio.options.headers["appVersionName"]="V 4.0.6"; ///发起get请求 Response response = await dio.get(url); ... } 9 dio 取消网络请求

实际开发中,例如我们退出一个页面时,如果网络请求没完成,就会行成内存泄露,所以需要在页面消毁时,取消网络请求,或者是在下载一个文件时,时间太长了,用户点击取消,就需要取消网络连接

///创建取消标志 CancelToken cancelToken = new CancelToken(); void getRequestFunction2() async { ///用户id int userId = 3; ///创建 dio Dio dio = new Dio(); ///请求地址 ///传参方式1 String url = "http://192.168.0.102:8080/getUser/$userId"; ///发起get请求 并设置 CancelToken 取消标志 Response response = await dio.get(url,cancelToken: cancelToken); ... }

那么当我们需要手动取消这个网络请求时,只需要调用如下方法

///取消网络请求 if(cancelToken!=null&&!cancelToken.isCancelled){ cancelToken.cancel(); cancelToken=null; }

需要注意的是,一个 cancelToken 只能对就一个网络请求。

完毕

在这里插入图片描述



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3